# -*- coding: UTF-8 -*-
from datetime import datetime
from enum import Enum
from typing import List

from pydantic import BaseModel, Field

from dispatcher.common_utils import constants


class IntervalRule(Enum):
    equal_difference = "equal_difference"  # 等差递增
    equal_ratio = "equal_ratio"  # 等比递增
    equal = "equal"  # 等值


class RetryTimeIntervalModel(BaseModel):
    interval: int = Field(description="重试时间间隔")
    rule: str = Field(description="重试间隔规则")
    time_intervals: List[int] = Field(description="自定义重试间隔")


class DispatchTaskState(Enum):
    COMMING = "COMMING"  # 调度系统刚接收到调度请求，在检查调度可行后转变为 RECEIVED
    RECEIVED = "RECEIVED"
    STARTED = "STARTED"
    RETRY = "RETRY"
    SUCCESS = "SUCCESS"
    FAILURE = "FAILURE"


# todo 定时任务可以先判断距离执行还有多长时间，阈值以内直接加载到redis中，以外就持久化，脚本跑补偿的时候再加载到内存
# 任务创建时间和最后一次修改时间直接放到表模型的构建上，不用在业务层处理
class DispatchTaskModel(BaseModel):
    # 初始化消息
    # task_type: str = Field(..., description="任务类型，用于判断使用哪种处理方式")
    task_type = DispatchTaskState.RECEIVED

    # 数据信息
    block_sn: str = Field(..., description="数据块唯一编号")
    data_block: str = Field(..., description="调度任务内容")  # 这应该是一个json，包含调度的url之类的信息

    # 任务信息
    task_id: str = Field(description="调度任务ID")  # todo 调度任务id不应该是一个str,唯一性可以靠block_sn保证
    dispatch_type: str = Field(default='timing', description="调度任务类型")  # todo 只有三种，即时任务，延时任务，定时任务 创建定时任务应该有另一个专门的接口
    state: DispatchTaskState = Field(description="调度任务状态")
    task_log: str = Field(description="任务执行日志")  # 这应该是一个json，记录每一次失败|成功的原因
    remain_try_times: datetime = Field(description="剩余尝试次数")
    max_try_times: int = Field(description="任务最大尝试次数")
    retry_time_interval: RetryTimeIntervalModel = Field(description="重试时间间隔")  # fixme 这里的各种规则还没有处理

    # 时间信息
    next_try_time: datetime = Field(description="任务下一次执行时间")  # todo 可能会删，由于使用celery导致任务状态的更新实时性下降，所以下次执行时间已经不是一个必要的字段
    last_try_time: datetime = Field(description="任务最后一次执行时间，过期后不再重试")
    delay_second: int = Field(description="任务剩余延时时间", le=constants.MAX_DELAY_SECOND)

    # 额外信息
    server: str = Field(..., description="调用方系统名称")
    remark: str = Field(description="备注信息")
    extend: str = Field(description="扩展信息")  # 这应该是一个Json



